// design project main.go
package main

import (
	"fmt"
	"go-design/adapter"
	"go-design/command"
	"go-design/composite"
	"go-design/decorator"
	"go-design/facade"
	"go-design/factory"
	"go-design/iterator"
	"go-design/observer"
	"go-design/proxy"
	"go-design/singleton"
	"go-design/state"
	"go-design/strategy"
	"go-design/template"
	"runtime"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	test()
}

func test() {
	//TestStrategy()

	//TestObserver()

	//TestDecorator()

	//TestFactory()

	//TestSingleton()

	//TestCommand()

	//TestAdapter()

	//TestFacade()

	//TestTemplate()

	//TestIterator()

	//TestComposite()

	//TestState()

	TestProxy()
}

func TestProxy() {
	fmt.Println("test proxy........")

	p := proxy.NewProxy(proxy.NewSchoolGirl("李娇娇"))

	p.GiveDolls()

	p.GiveFlowers()

	p.GiveChocolate()
}

func TestState() {
	fmt.Println("test state........")

	g := state.NewGumballMachine(2)

	g.InsertQuarter()
	g.TurnCrank()

	g.InsertQuarter()
	g.EjectQuarter()

	g.InsertQuarter()
	g.TurnCrank()

}

func TestComposite() {
	fmt.Println("test composite........")

	all := composite.NewMenu("ALL MENUS", "All menus combined")

	pancake := composite.NewMenu("PANCAKE HOUSE MENU", "Breakfast")
	diner := composite.NewMenu("DINER MENU", "Lunch")
	cafe := composite.NewMenu("CAFE MENU", "Dinner")
	dessert := composite.NewMenu("DESSERT MENU", "Dessert of course!")

	all.Add(pancake)
	all.Add(diner)
	all.Add(cafe)
	all.Add(dessert)

	diner.Add(composite.NewMenuItem("Pasta", "Spaghetti with Marinara Sauce, and a slice of sourdough bread", true, 3.89))
	dessert.Add(composite.NewMenuItem("Apple Pie", "Apple pie with a flakey crust, topped with vanilla ice cream", true, 1.59))

	w := composite.NewWaitress(all)

	w.PrintMenu()
}

func TestIterator() {
	fmt.Println("test iterator........")
	w := iterator.NewWaitress(iterator.NewPancakeHouseMenu(), iterator.NewDinerMenu())

	w.PrintMenu()
}

func TestTemplate() {
	fmt.Println("test template........")
	t := template.NewCaffeineBeverage(new(template.Tea))
	t.PrepareRecipe()

	t = template.NewCaffeineBeverage(new(template.Coffee))
	t.PrepareRecipe()
}

func TestFacade() {
	fmt.Println("test facade........")

	f := facade.NewHomeTheaterFacade(facade.Amplifier{}, facade.DvdPlayer{}, facade.Projector{},
		facade.TheaterLights{}, facade.Screen{}, facade.PopcornPopper{})

	f.WatchMovie()
	f.EndMovie()
}

func TestAdapter() {
	fmt.Println("test adapter........")
	var t adapter.WildTurkey
	ta := adapter.NewTurkeyAdapter(&t)
	var a adapter.Duck = ta
	a.Quack()
	a.Fly()
}

func TestCommand() {
	fmt.Println("test command........")
	r := command.NewRemoteControl()
	var light command.Light
	var garage command.GarageDoor
	var stereo command.Stereo
	lon := command.NewLightOnCommand(&light)
	lof := command.NewLightOffCommand(&light)
	gon := command.NewGarageDoorDownCommand(&garage)
	gof := command.NewGarageDoorUpCommand(&garage)
	son := command.NewStereoOnWithCDCommand(&stereo)
	sof := command.NewStereoOffCommand(&stereo)

	r.SetCommand(0, lon, lof)
	r.SetCommand(1, gon, gof)
	r.SetCommand(2, son, sof)

	r.OnButtonWasPushed(0)
	r.OffButtonWasPushed(0)
	r.OnButtonWasPushed(1)
	r.OffButtonWasPushed(1)
	r.OnButtonWasPushed(2)
	r.OffButtonWasPushed(2)
}

func TestSingleton() {
	fmt.Println("test singleton........")
	var s singleton.Singleton = singleton.GetInstance(3)
	s.PrintSome()
	s = singleton.GetInstance(5)
	s.PrintSome()
}

func TestFactory() {
	fmt.Println("test factory........")
	var n factory.PizzaStore = &factory.NYStylePizzaStore{}

	n.OrderPizza("cheese")

	var c factory.PizzaStore = &factory.ChicagoStylePizzaStore{}

	c.OrderPizza("veggie")
}

func TestDecorator() {
	fmt.Println("test decerator........")
	var d decorator.CondimentDecorator = decorator.NewMilk(&decorator.DarkRoast{})
	d = decorator.NewMocha(d)
	d = decorator.NewSoy(d)
	d = decorator.NewMocha(d)

	fmt.Println(d.Cost(), d.GetDescription())

}

func TestObserver() {
	fmt.Println("test observer........")
	d := observer.NewWeatherData()
	c := new(observer.CurrentConditionsDisplay)
	s := new(observer.StatisticsDisplay)
	f := new(observer.ForecastDisplay)
	t := new(observer.ThirdPartyDisplay)
	d.RegisterObserver(c)
	d.RegisterObserver(s)
	d.RegisterObserver(f)
	d.RegisterObserver(t)
	d.NotifyObserver()
	d.RemoveObserver(f)
	d.NotifyObserver()
}

func TestStrategy() {
	fmt.Println("test strategy........")
	var d strategy.Duck
	d = strategy.NewMallardDuck()
	fmt.Println("MallardDuck test....")
	d.Fly()
	d.Quack()

	d = strategy.NewRedHeadDuck()
	fmt.Println("RedHeadDuck test....")
	d.Fly()
	d.Quack()

	d = strategy.NewRubberDuck()
	fmt.Println("RubberDuck test....")
	d.Fly()
	d.Quack()

	d = strategy.NewDecoyDuck()
	fmt.Println("DecoyDuck test....")
	d.Fly()
	d.Quack()
}
